package com.liujit.standard.basis.admin.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liujit.standard.basis.admin.config.NacosConfig;
import com.liujit.standard.basis.admin.domain.params.LoginParam;
import com.liujit.standard.basis.admin.domain.params.UpdPasswordParam;
import com.liujit.standard.basis.admin.domain.result.LoginInfoResult;
import com.liujit.standard.basis.admin.mapper.SysMenuMapper;
import com.liujit.standard.basis.admin.mapper.SysUserMapper;
import com.liujit.standard.basis.admin.model.SysMenu;
import com.liujit.standard.basis.admin.model.SysUser;
import com.liujit.standard.basis.admin.model.SysUserRole;
import com.liujit.standard.basis.admin.service.SysUserRoleService;
import com.liujit.standard.basis.admin.service.SysUserService;
import com.liujit.standard.basis.admin.util.ApiUtil;
import com.liujit.standard.basis.core.constants.RedisConstants;
import com.liujit.standard.basis.core.domain.result.UserInfo;
import com.liujit.standard.basis.core.enums.ResultCode;
import com.liujit.standard.basis.core.exception.BusinessException;
import com.liujit.standard.basis.core.service.RedisService;
import com.liujit.standard.basis.core.util.CoreUtil;
import com.liujit.standard.basis.core.util.CryptoUtil;
import com.liujit.standard.basis.core.util.IdGenerator;
import com.liujit.standard.basis.core.util.JwtUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description 系统用户Service实现类
 * @Author LiuJun
 * @Date 2021-03-25 17:12:35
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private NacosConfig nacosConfig;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private RedisService redisService;

    @Override
    public String login(LoginParam param) {
        // 获取用户信息
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("login_name", param.getLoginName());
        SysUser user = sysUserMapper.selectOne(wrapper);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        if (user.getState() == 0) {
            throw new BusinessException(ResultCode.USER_ACCOUNT_FORBIDDEN);
        }
        // 密码错误
        String pass = CryptoUtil.MD5(user.getId() + param.getLoginPass());
        if (!user.getLoginPass().equals(pass)) {
            throw new BusinessException(ResultCode.USER_LOGIN_ERROR);
        }
        // 转换
        UserInfo userInfo = CoreUtil.modelMapper().map(user, UserInfo.class);
        // 向redis中存储用户信息 -- 30分钟过期
        String k = Convert.toStr(user.getId());
        String token = IdGenerator.getUUID();
        String oldToken = Convert.toStr(redisService.get(k));
        if (oldToken != null) {
            redisService.remove(oldToken);
        }
        redisService.set(k, token, 30L, TimeUnit.MINUTES);
        redisService.set(token, userInfo, 30L, TimeUnit.MINUTES);
        // 生成token(token包含用户id)
        Map jwtParam = new HashMap(16);
        jwtParam.put("token", token);
        return JwtUtils.generateJwt(jwtParam, 24 * 60 * 60 * 1000);
    }

    @Override
    public LoginInfoResult info() {
        LoginInfoResult result = new LoginInfoResult();
        UserInfo user = ApiUtil.getSysUser();
        result.setInfo(user);
        List<SysMenu> routers = getRouters(user.getId(), user.getLoginName());
        result.setRouters(routers);
        // 缓存权限 -- 根据ID查询用户权限
        List<SysMenu> authList = getAuths(user.getId(), user.getLoginName());
        List<String> auths = new ArrayList<>();
        for (SysMenu sm : authList) {
            if (StrUtil.isNotEmpty(sm.getAuthCode())) {
                auths.add(sm.getAuthCode());
            }
        }
        String authKey = RedisConstants.AUTH_PREFIX + user.getId();
        redisService.set(authKey, auths, 30L, TimeUnit.MINUTES);
        return result;
    }

    @Override
    public List<SysMenu> getRouters(Long userId, String loginName) {
        /*主宰拥有一切权限*/
        if (loginName.equals(nacosConfig.getSuperName())) {
            return sysMenuMapper.selectList(new QueryWrapper<>());
        } else {
            return sysUserMapper.selectRouters(userId, null);
        }
    }

    @Override
    public List<SysMenu> getAuths(Long userId, String loginName) {
        /*主宰拥有一切权限*/
        if (loginName.equals(nacosConfig.getSuperName())) {
            QueryWrapper wrapper = new QueryWrapper<>();
            wrapper.eq("menu_type", 3);
            return sysMenuMapper.selectList(wrapper);
        } else {
            return sysUserMapper.selectRouters(userId, 3);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String add(SysUser sysUser, List<Long> roleIds) {
        // 查询用户是否存在
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("login_name", sysUser.getLoginName());
        SysUser user = sysUserMapper.selectOne(wrapper);
        if (user != null) {
            throw new BusinessException(ResultCode.USER_HAS_EXISTED);
        }
        sysUser.setId(IdGenerator.getId());
        sysUser.setLoginPass(CryptoUtil.MD5(sysUser.getId() + CryptoUtil.MD5(nacosConfig.getDefPwd())));
        List<SysUserRole> list = new ArrayList<>();
        for (Long roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(roleId);
            list.add(sysUserRole);
        }
        sysUserRoleService.saveBatch(list);
        sysUserMapper.insert(sysUser);
        return nacosConfig.getDefPwd();
    }

    @Override
    public Boolean upd(SysUser sysUser, List<Long> roleIds) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user_id", sysUser.getId());
        sysUserRoleService.remove(wrapper);
        List<SysUserRole> list = new ArrayList<>();
        for (Long roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(roleId);
            list.add(sysUserRole);
        }
        sysUserRoleService.saveBatch(list);
        int res = sysUserMapper.updateById(sysUser);
        if (res > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean del(String id) {
        List<String> ids = Arrays.asList(id.split(","));
        // 清除用户角色
        for (String s : ids) {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("user_id", Convert.toLong(s));
            sysUserRoleService.remove(wrapper);
        }
        return removeByIds(ids);
    }

    @Override
    public Boolean updRole(Long userId, List<Long> roleIds) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user_id", userId);
        sysUserRoleService.remove(wrapper);
        List<SysUserRole> list = new ArrayList<>();
        for (Long roleId : roleIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(userId);
            sysUserRole.setRoleId(roleId);
            list.add(sysUserRole);
        }
        return sysUserRoleService.saveBatch(list);
    }

    @Override
    public Boolean checkPassword(String password) {
        SysUser sysUser = sysUserMapper.selectById(ApiUtil.getUserId());
        String pass = CryptoUtil.MD5(sysUser.getId() + password);
        if (!pass.equals(sysUser.getLoginPass())) {
            throw new BusinessException("旧密码不正确");
        }
        return true;
    }

    @Override
    public Boolean updPassword(UpdPasswordParam param) {
        SysUser sysUser = sysUserMapper.selectById(ApiUtil.getUserId());
        String pass = CryptoUtil.MD5(sysUser.getId() + param.getOldPassword());
        if (!pass.equals(sysUser.getLoginPass())) {
            throw new BusinessException("旧密码不正确");
        }
        // 更新密码
        String newPass = CryptoUtil.MD5(sysUser.getId() + param.getNewPassword());
        sysUser.setLoginPass(newPass);
        Integer res = sysUserMapper.updateById(sysUser);
        if (res == 1) {
            // 重新登录
            ApiUtil.removeToken();
            return true;
        }
        return false;
    }

}
